/******************************************************************************
 *
 *  Copyright (C) 2009-2018 Realtek Corporation.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
/******************************************************************************
 *
 *	Module Name:
 *	    hci_h5.c
 *
 *	Abstract:
 *	    Contain HCI transport send/receive functions for UART H5 Interface.
 *
 *	Major Change History:
 *	      When             Who       What
 *	    ---------------------------------------------------------------
 *	    2016-09-23      cc   modified
 *
 *	Notes:
 *	      This is designed for UART H5 HCI Interface in Android 8.0
 *
 ******************************************************************************/
#define LOG_TAG "bt_h5_int"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
#include <linux/wait.h>

#include "bt_hci_bdroid.h"
#include "bt_list.h"
#include "bt_skbuff.h"
#include "hci_h5_int.h"
#include "userial.h"
#include "userial_vendor.h"

typedef void (*tINT_CMD_CBACK)(void *p_mem);
/******************************************************************************
**  Constants & Macros
******************************************************************************/
#define H5_TRACE_DATA_ENABLE 0 // if you want to see data tx and rx, set H5_TRACE_DATA_ENABLE 1
#define H5_LOG_VERBOSE 0

unsigned int h5_log_enable = 1;

#ifndef H5_LOG_BUF_SIZE
#define H5_LOG_BUF_SIZE 1024
#endif
#define H5_LOG_MAX_SIZE (H5_LOG_BUF_SIZE - 12)

#ifndef H5_LOG_BUF_SIZE
#define H5_LOG_BUF_SIZE 1024
#endif
#define H5_LOG_MAX_SIZE (H5_LOG_BUF_SIZE - 12)

#define DATA_RETRANS_COUNT 40          // 40*100 = 4000ms(4s)
#define BT_INIT_DATA_RETRANS_COUNT 200 // 200*20 = 4000ms(4s)
#define SYNC_RETRANS_COUNT 350         // 350*10 = 3500ms(3.5s)
#define CONF_RETRANS_COUNT 350

#define DATA_RETRANS_TIMEOUT_VALUE 100        // ms
#define BT_INIT_DATA_RETRANS_TIMEOUT_VALUE 20 // ms
#define SYNC_RETRANS_TIMEOUT_VALUE 10
#define CONF_RETRANS_TIMEOUT_VALUE 20
#define WAIT_CT_BAUDRATE_READY_TIMEOUT_VALUE 5
#define H5_HW_INIT_READY_TIMEOUT_VALUE 4000 // 4

/* Maximum numbers of allowed internal
** outstanding command packets at any time
*/
#define INT_CMD_PKT_MAX_COUNT 8
#define INT_CMD_PKT_IDX_MASK 0x07

// HCI Event codes
#define HCI_CONNECTION_COMP_EVT 0x03
#define HCI_DISCONNECTION_COMP_EVT 0x05
#define HCI_COMMAND_COMPLETE_EVT 0x0E
#define HCI_COMMAND_STATUS_EVT 0x0F
#define HCI_NUM_OF_CMP_PKTS_EVT 0x13
#define HCI_BLE_EVT 0x3E

#define PATCH_DATA_FIELD_MAX_SIZE 252
#define READ_DATA_SIZE 16

// HCI data types //
#define H5_RELIABLE_PKT 0x01
#define H5_UNRELIABLE_PKT 0x00

#define H5_ACK_PKT 0x00
#define HCI_COMMAND_PKT 0x01
#define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04
#define H5_VDRSPEC_PKT 0x0E
#define H5_LINK_CTL_PKT 0x0F

#define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07)
#define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07)
#define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01)
#define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01)
#define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f)
#define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4))
#define H5_HDR_SIZE 4

#define H5_CFG_SLID_WIN(cfg) ((cfg)&0x07)
#define H5_CFG_OOF_CNTRL(cfg) (((cfg) >> 3) & 0x01)
#define H5_CFG_DIC_TYPE(cfg) (((cfg) >> 4) & 0x01)
#define H5_CFG_VER_NUM(cfg) (((cfg) >> 5) & 0x07)
#define H5_CFG_SIZE 1

/******************************************************************************
**  Local type definitions
******************************************************************************/
/* Callback function for the returned event of internal issued command */
typedef void (*tTIMER_HANDLE_CBACK)(union sigval sigval_value);

typedef struct {
    uint16_t opcode;      /* OPCODE of outstanding internal commands */
    tINT_CMD_CBACK cback; /* Callback function when return of internal
                           * command is received */
} tINT_CMD_Q;

typedef RTK_BUFFER sk_buff;

typedef enum H5_RX_STATE { H5_W4_PKT_DELIMITER, H5_W4_PKT_START, H5_W4_HDR, H5_W4_DATA, H5_W4_CRC } tH5_RX_STATE;

typedef enum H5_RX_ESC_STATE { H5_ESCSTATE_NOESC, H5_ESCSTATE_ESC } tH5_RX_ESC_STATE;

typedef enum H5_LINK_STATE { H5_UNINITIALIZED, H5_INITIALIZED, H5_ACTIVE } tH5_LINK_STATE;

#define H5_EVENT_RX 0x0001
#define H5_EVENT_EXIT 0x0200

static volatile uint8_t h5_retransfer_running = 0;
static volatile uint16_t h5_ready_events = 0;
static volatile uint8_t h5_data_ready_running = 0;
volatile int h5_init_datatrans_flag;

void set_h5_init_datatrans_flag(int flag)
{
    h5_init_datatrans_flag = flag;
}

void set_h5_log_enable(unsigned int enable)
{
    h5_log_enable = enable;
}

/* Control block for HCISU_H5 */
typedef struct HCI_H5_CB {
    HC_BT_HDR *p_rcv_msg;                      /* Buffer to hold current rx HCI message */
    uint32_t int_cmd_rsp_pending;              /* Num of internal cmds pending for ack */
    uint8_t int_cmd_rd_idx;                    /* Read index of int_cmd_opcode queue */
    uint8_t int_cmd_wrt_idx;                   /* Write index of int_cmd_opcode queue */
    tINT_CMD_Q int_cmd[INT_CMD_PKT_MAX_COUNT]; /* FIFO queue */

    tINT_CMD_CBACK cback_h5sync; /* Callback function when h5 sync */

    uint8_t sliding_window_size;
    uint8_t oof_flow_control;
    uint8_t dic_type;

    RTB_QUEUE_HEAD *unack; // Unack'ed packets queue
    RTB_QUEUE_HEAD *rel;   // Reliable packets queue

    RTB_QUEUE_HEAD *unrel;     // Unreliable packets queue
    RTB_QUEUE_HEAD *recv_data; // Unreliable packets queue

    uint8_t rxseq_txack; // rxseq == txack. // expected rx SeqNumber
    uint8_t rxack;       // Last packet sent by us that the peer ack'ed //

    uint8_t use_crc;
    uint8_t is_txack_req; // txack required? Do we need to send ack's to the peer? //

    // Reliable packet sequence number - used to assign seq to each rel pkt. */
    uint8_t msgq_txseq; // next pkt seq

    uint16_t message_crc;
    uint32_t rx_count; // expected pkts to recv

    tH5_RX_STATE rx_state;
    tH5_RX_ESC_STATE rx_esc_state;
    tH5_LINK_STATE link_estab_state;

    sk_buff *rx_skb;
    sk_buff *data_skb;
    sk_buff *internal_skb;

    timer_t timer_data_retrans;
    timer_t timer_sync_retrans;
    timer_t timer_conf_retrans;
    timer_t timer_wait_ct_baudrate_ready;
    timer_t timer_h5_hw_init_ready;

    uint32_t data_retrans_count;
    uint32_t sync_retrans_count;
    uint32_t conf_retrans_count;

    pthread_mutex_t mutex;
    pthread_cond_t cond;
    pthread_t thread_data_retrans;

    pthread_mutex_t data_mutex;
    pthread_cond_t data_cond;
    pthread_t thread_data_ready_cb;

    uint8_t cleanuping;
} tHCI_H5_CB;

static tHCI_H5_CB rtk_h5;
static pthread_mutex_t h5_wakeup_mutex = PTHREAD_MUTEX_INITIALIZER;

/******************************************************************************
**  Variables
******************************************************************************/

/* Num of allowed outstanding HCI CMD packets */
volatile int num_hci_cmd_pkts = 1;

/******************************************************************************
**  Static variables
******************************************************************************/
struct patch_struct {
    int nTxIndex;   // current sending pkt number
    int nTotal;     // total pkt number
    int nRxIndex;   // ack index from board
    int nNeedRetry; // if no response from board
};

/******************************************************************************
**  Static function
******************************************************************************/
static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback);
static int OsStartTimer(timer_t timerid, int msec, int mode);
static int OsStopTimer(timer_t timerid);
static uint16_t h5_wake_up(void);

static hci_h5_callbacks_t *h5_int_hal_callbacks;

/******************************************************************************
**  Externs
******************************************************************************/

// timer API for retransfer
int h5_alloc_data_retrans_timer(void);
int h5_free_data_retrans_timer(void);
int h5_stop_data_retrans_timer(void);
int h5_start_data_retrans_timer(void);

int h5_alloc_sync_retrans_timer(void);
int h5_free_sync_retrans_timer(void);
int h5_stop_sync_retrans_timer(void);
int h5_start_sync_retrans_timer(void);

int h5_alloc_conf_retrans_timer(void);
int h5_free_conf_retrans_timer(void);
int h5_stop_conf_retrans_timer(void);
int h5_start_conf_retrans_timer(void);

int h5_alloc_wait_controller_baudrate_ready_timer(void);
int h5_free_wait_controller_baudrate_ready_timer(void);
int h5_stop_wait_controller_baudrate_ready_timer(void);
int h5_start_wait_controller_baudrate_ready_timer(void);

int h5_alloc_hw_init_ready_timer(void);
int h5_free_hw_init_ready_timer(void);
int h5_stop_hw_init_ready_timer(void);
int h5_start_hw_init_ready_timer(void);

int h5_enqueue(IN sk_buff *skb);

// bite reverse in bytes
// 00000001 -> 10000000
// 00000100 -> 00100000
const uint8_t byte_rev_table[256] = {
    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48,
    0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4,
    0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c,
    0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2,
    0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a,
    0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e,
    0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21,
    0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55,
    0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd,
    0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b,
    0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
    0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f,
    0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
#ifndef H5_LOG_BUF_SIZE
#define H5_LOG_BUF_SIZE 1024
#endif
#define H5_LOG_MAX_SIZE (H5_LOG_BUF_SIZE - 12)

#define LOGI0(t, s)

static void H5LogMsg(const char *fmt_str, ...)
{
    static char buffer[H5_LOG_BUF_SIZE];
    if (h5_log_enable == 1) {
        va_list ap;
        va_start(ap, fmt_str);
        (void)vsnprintf_s(&buffer[0], H5_LOG_MAX_SIZE, H5_LOG_MAX_SIZE, fmt_str, ap);
        va_end(ap);

        LOGI0("H5: ", buffer);
    } else {
        return;
    }
}

#define P_BUF_2 2
#define P_BUF_3 3
#define P_BUF_4 4

static void rtkbt_h5_send_hw_error(void)
{
    unsigned char p_buf[100];
    const char *str = "host stack: h5 send error";
    int length = strlen(str) + 1 + P_BUF_4;
    p_buf[0] = HCIT_TYPE_EVENT;                    // event
    p_buf[1] = HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT; // firmwre event log
    p_buf[P_BUF_2] = strlen(str) + P_BUF_2;        // len
    p_buf[P_BUF_3] = 0x01;                         // host log opcode
    (void)strcpy_s((char *)&p_buf[P_BUF_4], length, str);
    userial_recv_rawdata_hook(p_buf, length);

    length = P_BUF_4;
    p_buf[0] = HCIT_TYPE_EVENT;        // event
    p_buf[1] = HCI_HARDWARE_ERROR_EVT; // hardware error
    p_buf[P_BUF_2] = 0x01;             // len
    p_buf[P_BUF_3] = 0xfb;             // h5 error code
    userial_recv_rawdata_hook(p_buf, length);
}

// reverse bit
static __inline uint8_t bit_rev8(uint8_t byte)
{
    return byte_rev_table[byte];
}

// reverse bit
static __inline uint16_t bit_rev16(uint16_t x)
{
#define REV_8 8
    return (bit_rev8(x & 0xff) << REV_8) | bit_rev8(x >> REV_8);
}

static const uint16_t crc_table[] = {0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387,
                                     0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f};

// Initialise the crc calculator
#define H5_CRC_INIT(x) x = 0xffff

/*******************************************************************************
**
** Function        ms_delay
**
** Description     sleep unconditionally for timeout milliseconds
**
** Returns         None
**
*******************************************************************************/
void ms_delay(uint32_t timeout)
{
    struct timespec delay;
    int err;

    if (timeout == 0) {
        return;
    }

#define TV_SEC_1000 1000
    delay.tv_sec = timeout / TV_SEC_1000;
    delay.tv_nsec = TV_SEC_1000 * TV_SEC_1000 * (timeout % TV_SEC_1000);

    /* [u]sleep can't be used because it uses SIGALRM */
    do {
        err = nanosleep(&delay, &delay);
    } while (err < 0 && errno == EINTR);
}
/***********************************************
//
//skb related functions
//
//
//
***********************************************/
uint8_t *skb_get_data(IN sk_buff *skb)
{
    return skb->Data;
}

uint32_t skb_get_data_length(IN sk_buff *skb)
{
    return skb->Length;
}

sk_buff *skb_alloc(IN unsigned int len)
{
    sk_buff *skb = (sk_buff *)RtbAllocate(len, 0);
    return skb;
}

void skb_free(IN OUT sk_buff **skb)
{
    RtbFree(*skb);
    *skb = NULL;
    return;
}

static void skb_unlink(sk_buff *skb, struct _RTB_QUEUE_HEAD *list)
{
    RtbRemoveNode(list, skb);
}

// increase the date length in sk_buffer by len,
// and return the increased header pointer
uint8_t *skb_put(OUT sk_buff *skb, IN uint32_t len)
{
    RTK_BUFFER *rtb = (RTK_BUFFER *)skb;

    return RtbAddTail(rtb, len);
}

// change skb->len to len
// !!! len should less than skb->len
void skb_trim(sk_buff *skb, unsigned int len)
{
    RTK_BUFFER *rtb = (RTK_BUFFER *)skb;
    uint32_t skb_len = skb_get_data_length(skb);

    RtbRemoveTail(rtb, (skb_len - len));
    return;
}

uint8_t skb_get_pkt_type(sk_buff *skb)
{
    return BT_CONTEXT(skb)->PacketType;
}

void skb_set_pkt_type(sk_buff *skb, uint8_t pkt_type)
{
    BT_CONTEXT(skb)->PacketType = pkt_type;
}

// decrease the data length in sk_buffer by len,
// and move the content forward to the header.
// the data in header will be removed.
void skb_pull(OUT sk_buff *skb, IN uint32_t len)
{
    RTK_BUFFER *rtb = (RTK_BUFFER *)skb;
    RtbRemoveHead(rtb, len);
    return;
}

sk_buff *skb_alloc_and_init(IN uint8_t PktType, IN uint8_t *Data, IN uint32_t DataLen)
{
    sk_buff *skb = skb_alloc(DataLen);
    if (skb == NULL) {
        return NULL;
    }
    (void)memcpy_s(skb_put(skb, DataLen), DataLen, Data, DataLen);
    skb_set_pkt_type(skb, PktType);

    return skb;
}

static void skb_queue_head(IN RTB_QUEUE_HEAD *skb_head, IN RTK_BUFFER *skb)
{
    RtbQueueHead(skb_head, skb);
}

static void skb_queue_tail(IN RTB_QUEUE_HEAD *skb_head, IN RTK_BUFFER *skb)
{
    RtbQueueTail(skb_head, skb);
}

static RTK_BUFFER *skb_dequeue_head(IN RTB_QUEUE_HEAD *skb_head)
{
    return RtbDequeueHead(skb_head);
}

static RTK_BUFFER *skb_dequeue_tail(IN RTB_QUEUE_HEAD *skb_head)
{
    return RtbDequeueTail(skb_head);
}

static uint32_t skb_queue_get_length(IN RTB_QUEUE_HEAD *skb_head)
{
    return RtbGetQueueLen(skb_head);
}

/**
 * Add "d" into crc scope, caculate the new crc value
 *
 * @param crc crc data
 * @param d one byte data
 */
static void h5_crc_update(uint16_t *crc, uint8_t d)
{
    uint16_t reg = *crc;

#define REG_4 4
    reg = (reg >> REG_4) ^ crc_table[(reg ^ d) & 0x000f];
    reg = (reg >> REG_4) ^ crc_table[(reg ^ (d >> REG_4)) & 0x000f];

    *crc = reg;
}

struct __una_u16 {
    uint16_t x;
};
/**
 * Get crc data.
 *
 * @param h5 realtek h5 struct
 * @return crc data
 */
static uint16_t h5_get_crc(tHCI_H5_CB *h5)
{
    uint16_t crc = 0;
    uint8_t *data = skb_get_data(h5->rx_skb) + skb_get_data_length(h5->rx_skb) - 2L;
    crc = data[1] + (data[0] << 8L);
    return crc;
}

/**
 * Just add 0xc0 at the end of skb,
 * we can also use this to add 0xc0 at start while there is no data in skb
 *
 * @param skb socket buffer
 */
static void h5_slip_msgdelim(sk_buff *skb)
{
    const char pkt_delim = 0xc0;
    errno_t ret = -1;
    if (ret == memcpy_s(skb_put(skb, 1), sizeof(char), &pkt_delim, 1)) {
        return;
    }
}

/**
 * Slip ecode one byte in h5 proto, as follows:
 * 0xc0 -> 0xdb, 0xdc
 * 0xdb -> 0xdb, 0xdd
 * 0x11 -> 0xdb, 0xde
 * 0x13 -> 0xdb, 0xdf
 * others will not change
 *
 * @param skb socket buffer
 * @c pure data in the one byte
 */
static void h5_slip_one_byte(sk_buff *skb, uint8_t unencode_form)
{
    const signed char esc_c0[2] = {0xdb, 0xdc};
    const signed char esc_db[2] = {0xdb, 0xdd};
    const signed char esc_11[2] = {0xdb, 0xde};
    const signed char esc_13[2] = {0xdb, 0xdf};
    errno_t ret = -1;

#define SKB_PUT_2 2
    switch (unencode_form) {
        case 0xc0:
            if (ret == memcpy_s(skb_put(skb, SKB_PUT_2), SKB_PUT_2, &esc_c0, SKB_PUT_2)) {
                return;
            }
            break;
        case 0xdb:
            if (ret == memcpy_s(skb_put(skb, SKB_PUT_2), SKB_PUT_2, &esc_db, SKB_PUT_2)) {
                return;
            }
            break;

        case 0x11: {
            if (rtk_h5.oof_flow_control) {
                (void)memcpy_s(skb_put(skb, SKB_PUT_2), SKB_PUT_2, &esc_11, SKB_PUT_2);
            } else {
                (void)memcpy_s(skb_put(skb, 1), sizeof(char), &unencode_form, 1);
            }
        }
            break;

        case 0x13: {
            if (rtk_h5.oof_flow_control) {
                (void)memcpy_s(skb_put(skb, SKB_PUT_2), SKB_PUT_2, &esc_13, SKB_PUT_2);
            } else {
                (void)memcpy_s(skb_put(skb, 1), sizeof(char), &unencode_form, 1);
            }
        }
            break;

        default:
            (void)memcpy_s(skb_put(skb, 1), sizeof(char), &unencode_form, 1);
    }
}

/**
 * Decode one byte in h5 proto, as follows:
 * 0xdb, 0xdc -> 0xc0
 * 0xdb, 0xdd -> 0xdb
 * 0xdb, 0xde -> 0x11
 * 0xdb, 0xdf -> 0x13
 * others will not change
 *
 * @param h5 realtek h5 struct
 * @byte pure data in the one byte
 */
static void h5_unslip_one_byte(tHCI_H5_CB *h5, unsigned char byte)
{
    const uint8_t c0 = 0xc0, db = 0xdb;
    const uint8_t oof1 = 0x11, oof2 = 0x13;
    uint8_t *hdr = (uint8_t *)skb_get_data(h5->rx_skb);

    if (H5_ESCSTATE_NOESC == h5->rx_esc_state) {
        if (byte == 0xdb) {
            h5->rx_esc_state = H5_ESCSTATE_ESC;
        } else {
            (void)memcpy_s(skb_put(h5->rx_skb, 1), sizeof(char), &byte, 1);
            // Check Pkt Header's CRC enable bit
            if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC) {
                h5_crc_update(&h5->message_crc, byte);
            }
            h5->rx_count--;
        }
    } else if (H5_ESCSTATE_ESC == h5->rx_esc_state) {
        switch (byte) {
            case 0xdc:
                (void)memcpy_s(skb_put(h5->rx_skb, 1), sizeof(char), &c0, 1);
                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC) {
                    h5_crc_update(&h5->message_crc, 0xc0);
                }
                h5->rx_esc_state = H5_ESCSTATE_NOESC;
                h5->rx_count--;
                break;
            case 0xdd:
                (void)memcpy_s(skb_put(h5->rx_skb, 1), sizeof(char), &db, 1);
                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC) {
                    h5_crc_update(&h5->message_crc, 0xdb);
                }
                h5->rx_esc_state = H5_ESCSTATE_NOESC;
                h5->rx_count--;
                break;
            case 0xde:
                (void)memcpy_s(skb_put(h5->rx_skb, 1), sizeof(char), &oof1, 1);
                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC) {
                    h5_crc_update(&h5->message_crc, oof1);
                }
                h5->rx_esc_state = H5_ESCSTATE_NOESC;
                h5->rx_count--;
                break;
            case 0xdf:
                (void)memcpy_s(skb_put(h5->rx_skb, 1), sizeof(char), &oof2, 1);
                if (H5_HDR_CRC(hdr) && h5->rx_state != H5_W4_CRC) {
                    h5_crc_update(&h5->message_crc, oof2);
                }
                h5->rx_esc_state = H5_ESCSTATE_NOESC;
                h5->rx_count--;
                break;
            default:
                HILOGE("Error: Invalid byte %02x after esc byte", byte);
                skb_free(&h5->rx_skb);
                h5->rx_skb = NULL;
                h5->rx_state = H5_W4_PKT_DELIMITER;
                h5->rx_count = 0;
                break;
        }
    }
}
/**
 * Prepare h5 packet, packet format as follow:
 *  | LSB 4 octets  | 0 ~4095| 2 MSB
 *  |packet header | payload | data integrity check |
 *
 * pakcket header fromat is show below:
 *  | LSB 3 bits         | 3 bits             | 1 bits                       | 1 bits          |
 *  | 4 bits     | 12 bits        | 8 bits MSB
 *  |sequence number | acknowledgement number | data integrity check present | reliable packet |
 *  |packet type | payload length | header checksum
 *
 * @param h5 realtek h5 struct
 * @param data pure data
 * @param len the length of data
 * @param pkt_type packet type
 * @return socket buff after prepare in h5 proto
 */
static sk_buff *h5_prepare_pkt(tHCI_H5_CB *h5, uint8_t *data, signed long len, signed long pkt_type)
{
    sk_buff *nskb;
    uint8_t hdr[4];
    uint16_t H5_CRC_INIT(h5_txmsg_crc);
    int rel, i;

    switch (pkt_type) {
        case HCI_ACLDATA_PKT:
        case HCI_COMMAND_PKT:
        case HCI_EVENT_PKT:
            rel = H5_RELIABLE_PKT; // reliable
            break;
        case H5_ACK_PKT:
        case H5_VDRSPEC_PKT:
        case H5_LINK_CTL_PKT:
        case HCI_SCODATA_PKT:
            rel = H5_UNRELIABLE_PKT; // unreliable
            break;
        default:
            HILOGE("Unknown packet type");
            return NULL;
    }

        // Max len of packet: (original len +4(h5 hdr) +2(crc))*2
        //   (because bytes 0xc0 and 0xdb are escaped, worst case is
        //   when the packet is all made of 0xc0 and 0xdb :) )
        //   + 2 (0xc0 delimiters at start and end).

#define SKB_2 2
#define SKB_3 3
#define SKB_4 4
#define SKB_6 6
#define SKB_8 8
    nskb = skb_alloc((len + SKB_6) * SKB_2 + SKB_2);
    if (!nskb) {
        H5LogMsg("nskb is NULL");
        return NULL;
    }

    // Add SLIP start byte: 0xc0
    h5_slip_msgdelim(nskb);
    // set AckNumber in SlipHeader
    hdr[0] = h5->rxseq_txack << SKB_3;
    h5->is_txack_req = 0;

    H5LogMsg("We request packet no(%u) to card", h5->rxseq_txack);
    H5LogMsg("Sending packet with seqno %u and wait %u", h5->msgq_txseq, h5->rxseq_txack);
    if (rel == H5_RELIABLE_PKT) {
        // set reliable pkt bit and SeqNumber
        hdr[0] |= 0x80 + h5->msgq_txseq;
        ++(h5->msgq_txseq);
        h5->msgq_txseq = (h5->msgq_txseq) & 0x07;
    }

    // set DicPresent bit
    if (h5->use_crc) {
        hdr[0] |= 0x40;
    }

    // set packet type and payload length
    hdr[1] = ((len << SKB_4) & 0xff) | pkt_type;
    hdr[SKB_2] = (uint8_t)(len >> SKB_4);
    // set checksum
    hdr[SKB_3] = ~(hdr[0] + hdr[1] + hdr[SKB_2]);

    // Put h5 header */
    for (i = 0; i < SKB_4; i++) {
        h5_slip_one_byte(nskb, hdr[i]);

        if (h5->use_crc) {
            h5_crc_update(&h5_txmsg_crc, hdr[i]);
        }
    }

    // Put payload */
    for (i = 0; i < len; i++) {
        h5_slip_one_byte(nskb, data[i]);

        if (h5->use_crc) {
            h5_crc_update(&h5_txmsg_crc, data[i]);
        }
    }

    // Put CRC */
    if (h5->use_crc) {
        h5_txmsg_crc = bit_rev16(h5_txmsg_crc);
        h5_slip_one_byte(nskb, (uint8_t)((h5_txmsg_crc >> SKB_8) & 0x00ff));
        h5_slip_one_byte(nskb, (uint8_t)(h5_txmsg_crc & 0x00ff));
    }

    // Add SLIP end byte: 0xc0
    h5_slip_msgdelim(nskb);
    return nskb;
}
/**
 * Removed controller acked packet from Host's unacked lists
 *
 * @param h5 realtek h5 struct
 */
static void h5_remove_acked_pkt(tHCI_H5_CB *h5)
{
    RT_LIST_HEAD *Head = NULL;
    RT_LIST_ENTRY *Iter = NULL, *Temp = NULL;
    RTK_BUFFER *skb = NULL;

    int pkts_to_be_removed = 0;
    int seqno = 0;
    int i = 0;

    pthread_mutex_lock(&h5_wakeup_mutex);

    seqno = h5->msgq_txseq;
    pkts_to_be_removed = RtbGetQueueLen(h5->unack);

    while (pkts_to_be_removed) {
        if (h5->rxack == seqno) {
            break;
        }

        pkts_to_be_removed--;
        seqno = (seqno - 1) & 0x07;
    }

    if (h5->rxack != seqno) {
        H5LogMsg("Peer acked invalid packet");
    }

    // remove ack'ed packet from bcsp->unack queue
    i = 0; //  number of pkts has been removed from un_ack queue.
    Head = (RT_LIST_HEAD *)(h5->unack);
    LIST_FOR_EACH_SAFELY(Iter, Temp, Head)
    {
        skb = LIST_ENTRY(Iter, sk_buff, List);
        if (i >= pkts_to_be_removed) {
            break;
        }

        skb_unlink(skb, h5->unack);
        skb_free(&skb);
        i++;
    }

    if (skb_queue_get_length(h5->unack) == 0) {
        h5_stop_data_retrans_timer();
        rtk_h5.data_retrans_count = 0;
    }

    if (i != pkts_to_be_removed) {
        H5LogMsg("Removed only (%u) out of (%u) pkts", i, pkts_to_be_removed);
    }

    pthread_mutex_unlock(&h5_wakeup_mutex);
}

static void hci_h5_send_sync_req(void)
{
    unsigned char h5sync[2] = {0x01, 0x7E};
    sk_buff *skb = NULL;

    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5sync, sizeof(h5sync));
    if (!skb) {
        HILOGE("skb_alloc_and_init fail!");
        return;
    }
    H5LogMsg("H5: --->>>send sync req");

    h5_enqueue(skb);
    h5_wake_up();

    return;
}

static void hci_h5_send_sync_resp(void)
{
    unsigned char h5syncresp[2] = {0x02, 0x7D};
    sk_buff *skb = NULL;

    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5syncresp, sizeof(h5syncresp));
    if (!skb) {
        HILOGE("skb_alloc_and_init fail!");
        return;
    }

    H5LogMsg("H5: --->>>send sync resp");
    h5_enqueue(skb);
    h5_wake_up();

    return;
}

static void hci_h5_send_conf_req(void)
{
    unsigned char h5conf[3] = {0x03, 0xFC, 0x14};
    sk_buff *skb = NULL;

    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5conf, sizeof(h5conf));
    if (!skb) {
        HILOGE("skb_alloc_and_init fail!");
        return;
    }

    H5LogMsg("H5: --->>>send conf req");
    h5_enqueue(skb);
    h5_wake_up();

    return;
}

static void hci_h5_send_conf_resp(void)
{
    unsigned char h5confresp[2] = {0x04, 0x7B};
    sk_buff *skb = NULL;

    skb = skb_alloc_and_init(H5_LINK_CTL_PKT, h5confresp, sizeof(h5confresp));
    if (!skb) {
        HILOGE("skb_alloc_and_init fail!");
        return;
    }

    H5LogMsg("H5: --->>>send conf resp");
    h5_enqueue(skb);
    h5_wake_up();

    return;
}

static void rtk_notify_hw_h5_init_result(uint8_t status)
{
    H5LogMsg("rtk_notify_hw_h5_init_result %d", status);
    uint8_t sync_event[6] = {0x0e, 0x04, 0x03, 0xee, 0xfc, status};
    // we need to make a sync event to bt
    sk_buff *rx_skb;
    rx_skb = skb_alloc_and_init(HCI_EVENT_PKT, sync_event, sizeof(sync_event));
    if (!rx_skb) {
        HILOGE("%s, rx_skb alloc fail!", __func__);
        return;
    }
    pthread_mutex_lock(&rtk_h5.data_mutex);
    skb_queue_tail(rtk_h5.recv_data, rx_skb);
    pthread_cond_signal(&rtk_h5.data_cond);
    pthread_mutex_unlock(&rtk_h5.data_mutex);
}

static sk_buff *h5_dequeue(void)
{
    sk_buff *skb = NULL;
    //   First of all, check for unreliable messages in the queue,
    //   since they have higher priority
    if ((skb = (sk_buff *)skb_dequeue_head(rtk_h5.unrel)) != NULL) {
        sk_buff *nskb = h5_prepare_pkt(&rtk_h5, skb_get_data(skb), skb_get_data_length(skb), skb_get_pkt_type(skb));
        if (nskb) {
            skb_free(&skb);
            return nskb;
        } else {
            skb_queue_head(rtk_h5.unrel, skb);
        }
    }
    //   Now, try to send a reliable pkt. We can only send a
    //   reliable packet if the number of packets sent but not yet ack'ed
    //   is < than the winsize

    if (RtbGetQueueLen(rtk_h5.unack) < rtk_h5.sliding_window_size &&
        (skb = (sk_buff *)skb_dequeue_head(rtk_h5.rel)) != NULL) {
        sk_buff *nskb = h5_prepare_pkt(&rtk_h5, skb_get_data(skb), skb_get_data_length(skb), skb_get_pkt_type(skb));
        if (nskb) {
            skb_queue_tail(rtk_h5.unack, skb);
            h5_start_data_retrans_timer();
            return nskb;
        } else {
            skb_queue_head(rtk_h5.rel, skb);
        }
    }
    //   We could not send a reliable packet, either because there are
    //   none or because there are too many unack'ed packets. Did we receive
    //   any packets we have not acknowledged yet
    if (rtk_h5.is_txack_req) {
        // if so, craft an empty ACK pkt and send it on BCSP unreliable
        // channel
        sk_buff *nskb = h5_prepare_pkt(&rtk_h5, NULL, 0, H5_ACK_PKT);
        return nskb;
    }
    // We have nothing to send
    return NULL;
}

int h5_enqueue(IN sk_buff *skb)
{
    // Pkt length must be less than 4095 bytes
    if (skb_get_data_length(skb) > 0xFFF) {
        HILOGE("skb len > 0xFFF");
        skb_free(&skb);
        return 0;
    }

    switch (skb_get_pkt_type(skb)) {
        case HCI_ACLDATA_PKT:
        case HCI_COMMAND_PKT:
            skb_queue_tail(rtk_h5.rel, skb);
            break;

        case H5_LINK_CTL_PKT:
        case H5_ACK_PKT:
        case H5_VDRSPEC_PKT:
        case HCI_SCODATA_PKT:
            skb_queue_tail(rtk_h5.unrel, skb); /* 3-wire LinkEstablishment */
            break;
        default:
            skb_free(&skb);
            break;
    }
    return 0;
}

static uint16_t h5_wake_up(void)
{
    uint16_t bytes_sent = 0;
    sk_buff *skb = NULL;
    uint8_t *data = NULL;
    uint32_t data_len = 0;

    pthread_mutex_lock(&h5_wakeup_mutex);
    while (NULL != (skb = h5_dequeue())) {
        data = skb_get_data(skb);
        data_len = skb_get_data_length(skb);
        // we adopt the hci_h5 interface to send data
        bytes_sent = h5_int_hal_callbacks->h5_int_transmit_data_cb(DATA_TYPE_H5, data, data_len);

        H5LogMsg("bytes_sent(%d)", bytes_sent);

#if H5_TRACE_DATA_ENABLE
        {
            uint32_t iTemp = 0;
            uint32_t iTempTotal = 16;
            H5LogMsg("H5 TX: length(%d)", data_len);
            if (iTempTotal > data_len) {
                iTempTotal = data_len;
            }
            for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
                H5LogMsg("0x%x", data[iTemp]);
            }
        }
#endif
        skb_free(&skb);
    }

    pthread_mutex_unlock(&h5_wakeup_mutex);
    return bytes_sent;
}

void h5_process_ctl_pkts(void)
{
    // process h5 link establish
    uint8_t cfg;

    sk_buff *skb = rtk_h5.rx_skb;

    unsigned char h5sync[2] = {0x01, 0x7E}, h5syncresp[2] = {0x02, 0x7D}, h5conf[3] = {0x03, 0xFC, 0x14},
                  h5confresp[2] = {0x04, 0x7B};

#define MEM_2 2
    if (rtk_h5.link_estab_state == H5_UNINITIALIZED) { // sync
        if (!memcmp(skb_get_data(skb), h5sync, MEM_2)) {
            H5LogMsg("H5: <<<---recv sync req");
            hci_h5_send_sync_resp();
        } else if (!memcmp(skb_get_data(skb), h5syncresp, MEM_2)) {
            H5LogMsg("H5: <<<---recv sync resp");
            h5_stop_sync_retrans_timer();
            rtk_h5.sync_retrans_count = 0;
            rtk_h5.link_estab_state = H5_INITIALIZED;

            // send config req
            hci_h5_send_conf_req();
            h5_start_conf_retrans_timer();
        }
    } else if (rtk_h5.link_estab_state == H5_INITIALIZED) { // config
        if (!memcmp(skb_get_data(skb), h5sync, 0x2)) {
            H5LogMsg("H5: <<<---recv sync req in H5_INITIALIZED");
            hci_h5_send_sync_resp();
        } else if (!memcmp(skb_get_data(skb), h5conf, 0x2)) {
            H5LogMsg("H5: <<<---recv conf req");
            hci_h5_send_conf_resp();
        } else if (!memcmp(skb_get_data(skb), h5confresp, 0x2)) {
            H5LogMsg("H5: <<<---recv conf resp");
            h5_stop_conf_retrans_timer();
            rtk_h5.conf_retrans_count = 0;

            rtk_h5.link_estab_state = H5_ACTIVE;
            // notify hw to download patch

            (void)memcpy_s(&cfg, H5_CFG_SIZE, skb_get_data(skb) + MEM_2, H5_CFG_SIZE);
            rtk_h5.sliding_window_size = H5_CFG_SLID_WIN(cfg);
            rtk_h5.oof_flow_control = H5_CFG_OOF_CNTRL(cfg);
            rtk_h5.dic_type = H5_CFG_DIC_TYPE(cfg);
            H5LogMsg("rtk_h5.sliding_window_size(%d), oof_flow_control(%d), dic_type(%d)", rtk_h5.sliding_window_size,
                     rtk_h5.oof_flow_control, rtk_h5.dic_type);
            if (rtk_h5.dic_type) {
                rtk_h5.use_crc = 1;
            }

            rtk_notify_hw_h5_init_result(0);
        } else {
            H5LogMsg("H5_INITIALIZED receive event, ingnore");
        }
    } else if (rtk_h5.link_estab_state == H5_ACTIVE) {
        if (!memcmp(skb_get_data(skb), h5sync, 0x2)) {
            H5LogMsg("H5: <<<---recv sync req in H5_ACTIVE");
            rtkbt_h5_send_hw_error();
            hci_h5_send_sync_resp();
            H5LogMsg("H5 : H5_ACTIVE transit to H5_UNINITIALIZED");
            rtk_h5.link_estab_state = H5_UNINITIALIZED;
            hci_h5_send_sync_req();
            h5_start_sync_retrans_timer();
        } else if (!memcmp(skb_get_data(skb), h5conf, 0x2)) {
            H5LogMsg("H5: <<<---recv conf req in H5_ACTIVE");
            hci_h5_send_conf_resp();
        } else if (!memcmp(skb_get_data(skb), h5confresp, 0x2)) {
            H5LogMsg("H5: <<<---recv conf resp in H5_ACTIVE, discard");
        } else {
            H5LogMsg("H5_ACTIVE receive unknown link control msg, ingnore");
        }
    }
}

uint8_t isRtkInternalCommand(uint16_t opcode)
{
    if (opcode == 0xFC17 || opcode == 0xFC6D || opcode == 0xFC61 || opcode == 0xFC20) {
        return 1;
    } else {
        return 0;
    }
}

/*****************************************************************************
 * Check if it's a hci frame, if it is, complete it with response or parse the cmd complete event
 *
 * @param skb socket buffer
 *
 ******************************************************************************/
static uint8_t hci_recv_frame(sk_buff *skb, uint8_t pkt_type)
{
    uint8_t intercepted = 0;
#if H5_TRACE_DATA_ENABLE
    uint8_t *data = skb_get_data(skb);
#endif
    uint32_t data_len = skb_get_data_length(skb);

    H5LogMsg("UART H5 RX: length = %d", data_len);

#if H5_TRACE_DATA_ENABLE
    {
        uint32_t iTemp = 0;
        uint32_t iTempTotal = 16;
        H5LogMsg("H5 RX: length(%d)", data_len);
        if (iTempTotal > data_len) {
            iTempTotal = data_len;
        }
        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
            H5LogMsg("0x%x", data[iTemp]);
        }
    }
#endif
    // we only intercept evt packet here
    if (pkt_type == HCI_EVENT_PKT) {
        uint8_t *p;
        uint8_t event_code;
        uint16_t opcode, len;
        p = (uint8_t *)skb_get_data(skb);

        event_code = *p++;
        len = *p++;
        H5LogMsg("hci_recv_frame event_code(0x%x), len = %d", event_code, len);
        if (event_code == HCI_COMMAND_COMPLETE_EVT) {
            num_hci_cmd_pkts = *p++;
            STREAM_TO_UINT16(opcode, p);

            if (opcode == HCI_VSC_UPDATE_BAUDRATE) {
                intercepted = 1;
                rtk_h5.internal_skb = skb;
                H5LogMsg("CommandCompleteEvent for command h5_start_wait_controller_baudrate_ready_timer (0x%04X)",
                         opcode);
                h5_start_wait_controller_baudrate_ready_timer();
            }
        }
    }

    H5LogMsg("hci_recv_frame intercepted = %d", intercepted);
    return intercepted;
}

/**
 * after rx data is parsed, and we got a rx frame saved in h5->rx_skb,
 * this routinue is called.
 * things todo in this function:
 * 1. check if it's a hci frame, if it is, complete it with response or ack
 * 2. see the ack number, free acked frame in queue
 * 3. reset h5->rx_state, set rx_skb to null.
 *
 * @param h5 realtek h5 struct
 *
 */
static uint8_t h5_complete_rx_pkt(tHCI_H5_CB *h5)
{
    int pass_up = 1;
    uint16_t eventtype = 0;
    uint8_t *h5_hdr = NULL;
    uint8_t pkt_type = 0;
    uint8_t status = 0;

    h5_hdr = (uint8_t *)skb_get_data(h5->rx_skb);
    H5LogMsg("SeqNumber(%d), AckNumber(%d)", H5_HDR_SEQ(h5_hdr), H5_HDR_ACK(h5_hdr));

#if H5_TRACE_DATA_ENABLE
    {
        uint32_t iTemp = 0;
        uint32_t iTempTotal = 16;
        uint32_t data_len = skb_get_data_length(h5->rx_skb);
        uint8_t *data = skb_get_data(h5->rx_skb);
        H5LogMsg("H5 RX: length(%d)", data_len);

        if (iTempTotal > data_len) {
            iTempTotal = data_len;
        }
        for (iTemp = 0; iTemp < iTempTotal; iTemp++) {
            H5LogMsg("0x%x", data[iTemp]);
        }
    }
#endif

    if (H5_HDR_RELIABLE(h5_hdr)) {
        H5LogMsg("Received reliable seqno %u from card", h5->rxseq_txack);
        pthread_mutex_lock(&h5_wakeup_mutex);
        h5->rxseq_txack = H5_HDR_SEQ(h5_hdr) + 1;
#define NUM_8 8
        h5->rxseq_txack %= NUM_8;
        h5->is_txack_req = 1;
        pthread_mutex_unlock(&h5_wakeup_mutex);
        // send down an empty ack if needed.
        h5_wake_up();
    }

    h5->rxack = H5_HDR_ACK(h5_hdr);
    pkt_type = H5_HDR_PKT_TYPE(h5_hdr);
    switch (pkt_type) {
        case HCI_ACLDATA_PKT:
            pass_up = 1;
            eventtype = MSG_HC_TO_STACK_HCI_ACL;
            break;

        case HCI_EVENT_PKT:
            pass_up = 1;
            eventtype = MSG_HC_TO_STACK_HCI_EVT;
            break;

        case HCI_SCODATA_PKT:
            pass_up = 1;
            eventtype = MSG_HC_TO_STACK_HCI_SCO;
            break;
        case HCI_COMMAND_PKT:
            pass_up = 1;
            eventtype = MSG_HC_TO_STACK_HCI_ERR;
            break;

        case H5_LINK_CTL_PKT:
            pass_up = 0;
            break;

        case H5_ACK_PKT:
            pass_up = 0;
            break;

        default:
            HILOGE("Unknown pkt type(%d)", H5_HDR_PKT_TYPE(h5_hdr));
            eventtype = MSG_HC_TO_STACK_HCI_ERR;
            pass_up = 0;
            break;
    }

    // remove h5 header and send packet to hci
    h5_remove_acked_pkt(h5);

    if (H5_HDR_PKT_TYPE(h5_hdr) == H5_LINK_CTL_PKT) {
        skb_pull(h5->rx_skb, H5_HDR_SIZE);
        h5_process_ctl_pkts();
    }

    // decide if we need to pass up.
    if (pass_up) {
        skb_pull(h5->rx_skb, H5_HDR_SIZE);
        skb_set_pkt_type(h5->rx_skb, pkt_type);

        // send command or  acl data it to bluedroid stack
        uint16_t len = 0;
        sk_buff *skb_complete_pkt = h5->rx_skb;

        /* Allocate a buffer for message */

        len = BT_HC_HDR_SIZE + skb_get_data_length(skb_complete_pkt);
        h5->p_rcv_msg = (HC_BT_HDR *)malloc(len);

        if (h5->p_rcv_msg) {
            /* Initialize buffer with received h5 data */
            h5->p_rcv_msg->offset = 0;
            h5->p_rcv_msg->layer_specific = 0;
            h5->p_rcv_msg->event = eventtype;
            h5->p_rcv_msg->len = skb_get_data_length(skb_complete_pkt);
            (void)memcpy_s((uint8_t *)(h5->p_rcv_msg + 1), skb_get_data_length(skb_complete_pkt),
                           skb_get_data(skb_complete_pkt), skb_get_data_length(skb_complete_pkt));
        }

        status = hci_recv_frame(skb_complete_pkt, pkt_type);

        if (h5->p_rcv_msg) {
            free(h5->p_rcv_msg);
        }

        if (!status) {
            pthread_mutex_lock(&rtk_h5.data_mutex);
            skb_queue_tail(rtk_h5.recv_data, h5->rx_skb);
            pthread_cond_signal(&rtk_h5.data_cond);
            pthread_mutex_unlock(&rtk_h5.data_mutex);
        }
    } else {
        // free ctl packet
        skb_free(&h5->rx_skb);
    }
    h5->rx_state = H5_W4_PKT_DELIMITER;
    rtk_h5.rx_skb = NULL;
    return pkt_type;
}

/**
 * Parse the receive data in h5 proto.
 *
 * @param h5 realtek h5 struct
 * @param data point to data received before parse
 * @param count num of data
 * @return reserved count
 */
static bool h5_recv(tHCI_H5_CB *h5, uint8_t *data, int count)
{
    uint8_t *ptr;
    uint8_t *skb_data = NULL;
    uint8_t *hdr = NULL;
    int temp = count;
    bool complete_packet = false;

    ptr = (uint8_t *)data;
    while (temp) {
        if (h5->rx_count) {
            if (*ptr == 0xc0) {
                HILOGE("short h5 packet");
                skb_free(&h5->rx_skb);
                h5->rx_state = H5_W4_PKT_START;
                h5->rx_count = 0;
            } else {
                h5_unslip_one_byte(h5, *ptr);
            }

            ptr++;
            temp--;
            continue;
        }

        switch (h5->rx_state) {
            case H5_W4_HDR:
                // check header checksum. see Core Spec V4 "3-wire uart" page 67
                skb_data = skb_get_data(h5->rx_skb);
                hdr = (uint8_t *)skb_data;

#define SKB_DATA_2 2
#define SKB_DATA_3 3
                if ((0xff & (uint8_t) ~(skb_data[0] + skb_data[1] + skb_data[SKB_DATA_2])) != skb_data[SKB_DATA_3]) {
                    HILOGE("h5 hdr checksum error!!!");
                    skb_free(&h5->rx_skb);
                    h5->rx_state = H5_W4_PKT_DELIMITER;
                    h5->rx_count = 0;
                    continue;
                }

                if (H5_HDR_RELIABLE(hdr) && (H5_HDR_SEQ(hdr) != h5->rxseq_txack)) {
                    HILOGE("Out-of-order packet arrived, got(%u)expected(%u)", H5_HDR_SEQ(hdr), h5->rxseq_txack);
                    h5->is_txack_req = 1;
                    h5_wake_up();

                    skb_free(&h5->rx_skb);
                    h5->rx_state = H5_W4_PKT_DELIMITER;
                    h5->rx_count = 0;

                    continue;
                }
                h5->rx_state = H5_W4_DATA;
                // payload length: May be 0
                h5->rx_count = H5_HDR_LEN(hdr);
                continue;
            case H5_W4_DATA:
                hdr = (uint8_t *)skb_get_data(h5->rx_skb);
                if (H5_HDR_CRC(hdr)) { // pkt with crc /
                    h5->rx_state = H5_W4_CRC;
#define RX_COUNT_2 2
                    h5->rx_count = RX_COUNT_2;
                } else {
                    h5_complete_rx_pkt(h5); // Send ACK
                    complete_packet = true;
                    H5LogMsg("--------> H5_W4_DATA ACK\n");
                }
                continue;

            case H5_W4_CRC:
                if (bit_rev16(h5->message_crc) != h5_get_crc(h5)) {
                    HILOGE("Checksum failed, computed(%04x)received(%04x)", bit_rev16(h5->message_crc), h5_get_crc(h5));
                    skb_free(&h5->rx_skb);
                    h5->rx_state = H5_W4_PKT_DELIMITER;
                    h5->rx_count = 0;
                    continue;
                }
#define SKB_GET_LENTH_2 2
                skb_trim(h5->rx_skb, skb_get_data_length(h5->rx_skb) - SKB_GET_LENTH_2);
                h5_complete_rx_pkt(h5);
                complete_packet = true;
                continue;

            case H5_W4_PKT_DELIMITER:
                switch (*ptr) {
                    case 0xc0:
                        h5->rx_state = H5_W4_PKT_START;
                        break;
                    default:
                        break;
                }
                ptr++;
                temp--;
                break;

            case H5_W4_PKT_START:
                switch (*ptr) {
                    case 0xc0:
                        ptr++;
                        temp--;
                        break;
                    default:
                        h5->rx_state = H5_W4_HDR;
#define RX_COUNT_4 4
                        h5->rx_count = RX_COUNT_4;
                        h5->rx_esc_state = H5_ESCSTATE_NOESC;
                        H5_CRC_INIT(h5->message_crc);

                        // Do not increment ptr or decrement count
                        // Allocate packet. Max len of a H5 pkt=
                        // 0xFFF (payload) +4 (header) +2 (crc)
                        h5->rx_skb = skb_alloc(0x1005);
                        if (!h5->rx_skb) {
                            h5->rx_state = H5_W4_PKT_DELIMITER;
                            h5->rx_count = 0;
                            return false;
                        }
                        break;
                }
                break;
        }
    }
    return complete_packet;
}

/******************************************************************************
**  Static functions
******************************************************************************/
static void data_ready_cb_thread(void *arg)
{
    RTK_UNUSED(arg);
    sk_buff *skb;
    uint8_t pkt_type = 0;
    unsigned int total_length = 0;

    H5LogMsg("data_ready_cb_thread started");

    prctl(PR_SET_NAME, (unsigned long)"data_ready_cb_thread", 0, 0, 0);

    while (h5_data_ready_running) {
        pthread_mutex_lock(&rtk_h5.data_mutex);
        while (h5_data_ready_running && (skb_queue_get_length(rtk_h5.recv_data) == 0)) {
            pthread_cond_wait(&rtk_h5.data_cond, &rtk_h5.data_mutex);
        }
        pthread_mutex_unlock(&rtk_h5.data_mutex);

        if (h5_data_ready_running && (skb = skb_dequeue_head(rtk_h5.recv_data)) != NULL) {
            rtk_h5.data_skb = skb;
        } else {
            continue;
        }

        pkt_type = skb_get_pkt_type(rtk_h5.data_skb);
        total_length = skb_get_data_length(rtk_h5.data_skb);
        h5_int_hal_callbacks->h5_data_ready_cb(pkt_type, total_length);
    }

    H5LogMsg("data_ready_cb_thread exiting");
    pthread_exit(NULL);
}

static void data_retransfer_thread(void *arg)
{
    RTK_UNUSED(arg);
    uint16_t events;
    uint16_t data_retrans_counts = DATA_RETRANS_COUNT;

    H5LogMsg("data_retransfer_thread started");

    prctl(PR_SET_NAME, (unsigned long)"data_retransfer_thread", 0, 0, 0);

    while (h5_retransfer_running) {
        pthread_mutex_lock(&rtk_h5.mutex);
        while (h5_ready_events == 0) {
            pthread_cond_wait(&rtk_h5.cond, &rtk_h5.mutex);
        }
        events = h5_ready_events;
        h5_ready_events = 0;
        pthread_mutex_unlock(&rtk_h5.mutex);

        if (events & H5_EVENT_RX) {
            sk_buff *skb;
            HILOGE("retransmitting (%u) pkts, retransfer count(%d)", skb_queue_get_length(rtk_h5.unack),
                   rtk_h5.data_retrans_count);
            if (h5_init_datatrans_flag == 0) {
                data_retrans_counts = DATA_RETRANS_COUNT;
            } else {
                data_retrans_counts = BT_INIT_DATA_RETRANS_COUNT;
            }

            if (rtk_h5.data_retrans_count < data_retrans_counts) {
                pthread_mutex_lock(&h5_wakeup_mutex);
                while ((skb = skb_dequeue_tail(rtk_h5.unack)) != NULL) {
#if H5_TRACE_DATA_ENABLE
                    uint32_t data_len = skb_get_data_length(skb);
                    uint8_t *pdata = skb_get_data(skb);
#define DATA_LEN_16 16
                    if (data_len > DATA_LEN_16) {
                        data_len = DATA_LEN_16;
                    }

                    for (i = 0; i < data_len; i++) {
                        HILOGE("0x%02X", pdata[i]);
                    }
#endif
                    rtk_h5.msgq_txseq = (rtk_h5.msgq_txseq - 1) & 0x07;
                    skb_queue_head(rtk_h5.rel, skb);
                }
                pthread_mutex_unlock(&h5_wakeup_mutex);
                rtk_h5.data_retrans_count++;
                h5_wake_up();
            } else {
                // do not put packet to rel queue, and do not send
                // Kill bluetooth
                rtkbt_h5_send_hw_error();
            }
        } else if (events & H5_EVENT_EXIT) {
            break;
        }
    }

    H5LogMsg("data_retransfer_thread exiting");
    pthread_exit(NULL);
}

void h5_retransfer_signal_event(uint16_t event)
{
    pthread_mutex_lock(&rtk_h5.mutex);
    h5_ready_events |= event;
    pthread_cond_signal(&rtk_h5.cond);
    pthread_mutex_unlock(&rtk_h5.mutex);
}

static int create_data_retransfer_thread(void)
{
    pthread_attr_t thread_attr;

    if (h5_retransfer_running) {
        HILOGW("create_data_retransfer_thread has been called repeatedly without calling cleanup ?");
    }

    h5_retransfer_running = 1;
    h5_ready_events = 0;

    pthread_attr_init(&thread_attr);
    pthread_mutex_init(&rtk_h5.mutex, NULL);
    pthread_cond_init(&rtk_h5.cond, NULL);

    if (pthread_create(&rtk_h5.thread_data_retrans, &thread_attr, (void *)data_retransfer_thread, NULL) != 0) {
        HILOGE("pthread_create thread_data_retrans failed!");
        h5_retransfer_running = 0;
        return -1;
    }
    return 0;
}

static int create_data_ready_cb_thread(void)
{
    pthread_attr_t thread_attr;

    if (h5_data_ready_running) {
        HILOGW("create_data_ready_cb_thread has been called repeatedly without calling cleanup ?");
    }

    h5_data_ready_running = 1;

    pthread_attr_init(&thread_attr);
    pthread_mutex_init(&rtk_h5.data_mutex, NULL);
    pthread_cond_init(&rtk_h5.data_cond, NULL);

    if (pthread_create(&rtk_h5.thread_data_ready_cb, &thread_attr, (void *)data_ready_cb_thread, NULL) != 0) {
        HILOGE("pthread_create thread_data_ready_cb failed!");
        h5_data_ready_running = 0;
        return -1;
    }
    return 0;
}

/*****************************************************************************
**   HCI H5 INTERFACE FUNCTIONS
*****************************************************************************/

/*******************************************************************************
**
** Function        hci_h5_init
**
** Description     Initialize H5 module
**
** Returns         None
**
*******************************************************************************/
void hci_h5_int_init(hci_h5_callbacks_t *h5_callbacks)
{
    H5LogMsg("hci_h5_int_init");

    h5_int_hal_callbacks = h5_callbacks;
    (void)memset_s(&rtk_h5, sizeof(tHCI_H5_CB), 0, sizeof(tHCI_H5_CB));

    /* Per HCI spec., always starts with 1 */
    num_hci_cmd_pkts = 1;

    h5_alloc_data_retrans_timer();
    h5_alloc_sync_retrans_timer();
    h5_alloc_conf_retrans_timer();
    h5_alloc_wait_controller_baudrate_ready_timer();
    h5_alloc_hw_init_ready_timer();

    rtk_h5.thread_data_retrans = (pthread_t)-1;

    rtk_h5.recv_data = RtbQueueInit();

    if (create_data_ready_cb_thread() != 0) {
        HILOGE("H5 create_data_ready_cb_thread failed");
    }

    if (create_data_retransfer_thread() != 0) {
        HILOGE("H5 create_data_retransfer_thread failed");
    }

    rtk_h5.unack = RtbQueueInit();
    rtk_h5.rel = RtbQueueInit();
    rtk_h5.unrel = RtbQueueInit();

    rtk_h5.rx_state = H5_W4_PKT_DELIMITER;
    rtk_h5.rx_esc_state = H5_ESCSTATE_NOESC;

    h5_init_datatrans_flag = 1;
}

/*******************************************************************************
**
** Function        hci_h5_cleanup
**
** Description     Clean H5 module
**
** Returns         None
**
*******************************************************************************/
void hci_h5_cleanup(void)
{
    H5LogMsg("hci_h5_cleanup");
    int result;

    rtk_h5.cleanuping = 1;

    h5_free_data_retrans_timer();
    h5_free_sync_retrans_timer();
    h5_free_conf_retrans_timer();
    h5_free_wait_controller_baudrate_ready_timer();
    h5_free_hw_init_ready_timer();

    if (h5_data_ready_running) {
        h5_data_ready_running = 0;
        pthread_mutex_lock(&rtk_h5.data_mutex);
        pthread_cond_signal(&rtk_h5.data_cond);
        pthread_mutex_unlock(&rtk_h5.data_mutex);
        if ((result = pthread_join(rtk_h5.thread_data_ready_cb, NULL)) < 0) {
            HILOGE("H5 thread_data_ready_cb pthread_join() FAILED result:%d", result);
        }
    }

    if (h5_retransfer_running) {
        h5_retransfer_running = 0;
        h5_retransfer_signal_event(H5_EVENT_EXIT);
        if ((result = pthread_join(rtk_h5.thread_data_retrans, NULL)) < 0) {
            HILOGE("H5 pthread_join() FAILED result:%d", result);
        }
    }

    pthread_mutex_destroy(&rtk_h5.mutex);
    pthread_mutex_destroy(&rtk_h5.data_mutex);
    pthread_cond_destroy(&rtk_h5.cond);
    pthread_cond_destroy(&rtk_h5.data_cond);

    RtbQueueFree(rtk_h5.unack);
    RtbQueueFree(rtk_h5.rel);
    RtbQueueFree(rtk_h5.unrel);

    h5_int_hal_callbacks = NULL;
    rtk_h5.internal_skb = NULL;
}

/*******************************************************************************
**
** Function        hci_h5_receive_msg
**
** Description     Construct HCI EVENT/ACL packets and send them to stack once
**                 complete packet has been received.
**
** Returns         Number of read bytes
**
*******************************************************************************/
bool hci_h5_receive_msg(uint8_t *byte, uint16_t length)
{
    bool status = false;
    status = h5_recv(&rtk_h5, byte, length);
    return status;
}

size_t hci_h5_int_read_data(uint8_t *data_buffer, size_t max_size)
{
    H5LogMsg("hci_h5_int_read_data need_size = %d", max_size);
    if (!rtk_h5.data_skb) {
        HILOGE("hci_h5_int_read_data, there is no data to read for this packet!");
        return -1;
    }
    sk_buff *skb_complete_pkt = rtk_h5.data_skb;
    uint8_t *data = skb_get_data(skb_complete_pkt);
    uint32_t data_len = skb_get_data_length(skb_complete_pkt);

    H5LogMsg("hci_h5_int_read_data length = %d, need_size = %d", data_len, max_size);
    if (data_len <= max_size) {
        (void)memcpy_s(data_buffer, data_len, data, data_len);
        skb_free(&rtk_h5.data_skb);
        rtk_h5.data_skb = NULL;
        return data_len;
    } else {
        (void)memcpy_s(data_buffer, max_size, data, max_size);
        skb_pull(rtk_h5.data_skb, max_size);
        return max_size;
    }
}

/*******************************************************************************
**
** Function        hci_h5_send_cmd
**
** Description     get cmd data from hal and send cmd
**
**
** Returns          bytes send
**
*******************************************************************************/
uint16_t hci_h5_send_cmd(serial_data_type_t type, uint8_t *data, uint16_t length)
{
    sk_buff *skb = NULL;
    uint16_t bytes_to_send, opcode;

    if (type != DATA_TYPE_COMMAND) {
        HILOGE("%s Receive wrong type type : %d", __func__, type);
        return -1;
    }

    skb = skb_alloc_and_init(type, data, length);
    if (!skb) {
        HILOGE("send cmd skb_alloc_and_init fail!");
        return -1;
    }

    h5_enqueue(skb);

    num_hci_cmd_pkts--;

    /* If this is an internal Cmd packet, the layer_specific field would
     * have stored with the opcode of HCI command.
     * Retrieve the opcode from the Cmd packet.
     */
    STREAM_TO_UINT16(opcode, data);
    H5LogMsg("HCI Command opcode(0x%04X)", opcode);
    if (opcode == 0x0c03) {
        H5LogMsg("RX HCI RESET Command, stop hw init timer");
        h5_stop_hw_init_ready_timer();
    }
    bytes_to_send = h5_wake_up();
    return length;
}

/*******************************************************************************
**
** Function        hci_h5_send_acl_data
**
** Description     get cmd data from hal and send cmd
**
**
** Returns          bytes send
**
*******************************************************************************/
uint16_t hci_h5_send_acl_data(serial_data_type_t type, uint8_t *data, uint16_t length)
{
    uint16_t bytes_to_send;
    sk_buff *skb = NULL;

    skb = skb_alloc_and_init(type, data, length);
    if (!skb) {
        HILOGE("hci_h5_send_acl_data, alloc skb buffer fail!");
        return -1;
    }

    h5_enqueue(skb);

    bytes_to_send = h5_wake_up();
    return length;
}

/*******************************************************************************
**
** Function        hci_h5_send_sco_data
**
** Description     get sco data from hal and send sco data
**
**
** Returns          bytes send
**
*******************************************************************************/
uint16_t hci_h5_send_sco_data(serial_data_type_t type, uint8_t *data, uint16_t length)
{
    sk_buff *skb = NULL;
    uint16_t bytes_to_send;

    skb = skb_alloc_and_init(type, data, length);
    if (!skb) {
        HILOGE("send sco data skb_alloc_and_init fail!");
        return -1;
    }

    h5_enqueue(skb);

    bytes_to_send = h5_wake_up();
    return length;
}

/*******************************************************************************
**
** Function        hci_h5_send_sync_cmd
**
** Description     Place the internal commands (issued internally by vendor lib)
**                 in the tx_q.
**
** Returns         TRUE/FALSE
**
*******************************************************************************/
uint8_t hci_h5_send_sync_cmd(uint16_t opcode, uint8_t *p_buf, uint16_t length)
{
    if (p_buf != NULL) {
        H5LogMsg("hci_h5_send_sync_cmd buf is not null");
    }
    if (rtk_h5.link_estab_state == H5_UNINITIALIZED) {
        if (opcode == HCI_VSC_H5_INIT) {
            h5_start_hw_init_ready_timer();
            hci_h5_send_sync_req();
            h5_start_sync_retrans_timer();
        }
    } else if (rtk_h5.link_estab_state == H5_ACTIVE) {
        H5LogMsg("hci_h5_send_sync_cmd(0x%x), link_estab_state = %d, length = %d", opcode, rtk_h5.link_estab_state,
                 length);
        return false;
    }

    return true;
}

/***
    Timer related functions
*/
static timer_t OsAllocateTimer(tTIMER_HANDLE_CBACK timer_callback)
{
    struct sigevent sigev;
    timer_t timerid;

    (void)memset_s(&sigev, sizeof(struct sigevent), 0, sizeof(struct sigevent));
    // Create the POSIX timer to generate signo
    sigev.sigev_notify = SIGEV_THREAD;
    sigev.sigev_notify_function = timer_callback;
    sigev.sigev_value.sival_ptr = &timerid;

    HILOGE("OsAllocateTimer rtk_parse sigev.sigev_notify_thread_id = syscall(__NR_gettid)!");
    // Create the Timer using timer_create signal

    if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == 0) {
        return timerid;
    } else {
        HILOGE("timer_create error!");
        return (timer_t)-1;
    }
}

static int OsFreeTimer(timer_t timerid)
{
    int ret = 0;
    ret = timer_delete(timerid);
    if (ret != 0) {
        HILOGE("timer_delete fail with errno(%d)", errno);
    }

    return ret;
}

static int OsStartTimer(timer_t timerid, int msec, int mode)
{
    struct itimerspec itval;

#define HCI_H5_MSEC_1000 1000
    itval.it_value.tv_sec = msec / HCI_H5_MSEC_1000;
    itval.it_value.tv_nsec = (long)(msec % HCI_H5_MSEC_1000) * (1000000L);

    if (mode == 1) {
        itval.it_interval.tv_sec = itval.it_value.tv_sec;
        itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
    } else {
        itval.it_interval.tv_sec = 0;
        itval.it_interval.tv_nsec = 0;
    }

    // Set the Timer when to expire through timer_settime

    if (timer_settime(timerid, 0, &itval, NULL) != 0) {
        HILOGE("time_settime error!");
        return -1;
    }

    return 0;
}

static int OsStopTimer(timer_t timerid)
{
    return OsStartTimer(timerid, 0, 0);
}

static void h5_retransfer_timeout_handler(union sigval sigev_value)
{
    RTK_UNUSED(sigev_value);
    H5LogMsg("h5_retransfer_timeout_handler");
    if (rtk_h5.cleanuping) {
        HILOGE("h5_retransfer_timeout_handler H5 is cleanuping, EXIT here!");
        return;
    }
    h5_retransfer_signal_event(H5_EVENT_RX);
}

static void h5_sync_retrans_timeout_handler(union sigval sigev_value)
{
    RTK_UNUSED(sigev_value);
    H5LogMsg("h5_sync_retrans_timeout_handler");
    if (rtk_h5.cleanuping) {
        HILOGE("h5_sync_retrans_timeout_handler H5 is cleanuping, EXIT here!");
        return;
    }
    if (rtk_h5.sync_retrans_count < SYNC_RETRANS_COUNT) {
        hci_h5_send_sync_req();
        rtk_h5.sync_retrans_count++;
    } else {
        if (rtk_h5.link_estab_state == H5_UNINITIALIZED) {
            rtk_notify_hw_h5_init_result(0x03);
        }
        h5_stop_sync_retrans_timer();
    }
}

static void h5_conf_retrans_timeout_handler(union sigval sigev_value)
{
    RTK_UNUSED(sigev_value);
    H5LogMsg("h5_conf_retrans_timeout_handler");
    if (rtk_h5.cleanuping) {
        HILOGE("h5_conf_retrans_timeout_handler H5 is cleanuping, EXIT here!");
        return;
    }

    H5LogMsg("Wait H5 Conf Resp timeout, %d times", rtk_h5.conf_retrans_count);
    if (rtk_h5.conf_retrans_count < CONF_RETRANS_COUNT) {
        hci_h5_send_conf_req();
        rtk_h5.conf_retrans_count++;
    } else {
        if (rtk_h5.link_estab_state != H5_ACTIVE) {
            rtk_notify_hw_h5_init_result(0x03);
        }
        h5_stop_conf_retrans_timer();
    }
}

static void h5_wait_controller_baudrate_ready_timeout_handler(union sigval sigev_value)
{
    RTK_UNUSED(sigev_value);
    H5LogMsg("h5_wait_ct_baundrate_ready_timeout_handler");
    if (rtk_h5.cleanuping) {
        HILOGE("h5_wait_controller_baudrate_ready_timeout_handler H5 is cleanuping, EXIT here!");
        if (rtk_h5.internal_skb) {
            skb_free(&rtk_h5.internal_skb);
        }
        return;
    }
    H5LogMsg("No Controller retransfer, baudrate of controller ready");
    pthread_mutex_lock(&rtk_h5.data_mutex);
    skb_queue_tail(rtk_h5.recv_data, rtk_h5.internal_skb);
    pthread_cond_signal(&rtk_h5.data_cond);
    pthread_mutex_unlock(&rtk_h5.data_mutex);

    rtk_h5.internal_skb = NULL;
}

static void h5_hw_init_ready_timeout_handler(union sigval sigev_value)
{
    RTK_UNUSED(sigev_value);
    H5LogMsg("h5_hw_init_ready_timeout_handler");
    if (rtk_h5.cleanuping) {
        HILOGE("H5 is cleanuping, EXIT here!");
        return;
    }
    H5LogMsg("TIMER_H5_HW_INIT_READY timeout, kill restart BT");
}

/*
** h5 data retrans timer functions
*/
int h5_alloc_data_retrans_timer(void)
{
    // Create and set the timer when to expire
    rtk_h5.timer_data_retrans = OsAllocateTimer(h5_retransfer_timeout_handler);

    return 0;
}

int h5_free_data_retrans_timer(void)
{
    return OsFreeTimer(rtk_h5.timer_data_retrans);
}

int h5_start_data_retrans_timer(void)
{
    if (h5_init_datatrans_flag == 0) {
        return OsStartTimer(rtk_h5.timer_data_retrans, DATA_RETRANS_TIMEOUT_VALUE, 0);
    } else {
        return OsStartTimer(rtk_h5.timer_data_retrans, BT_INIT_DATA_RETRANS_TIMEOUT_VALUE, 0);
    }
}

int h5_stop_data_retrans_timer(void)
{
    return OsStopTimer(rtk_h5.timer_data_retrans);
}

/*
** h5 sync retrans timer functions
*/
int h5_alloc_sync_retrans_timer(void)
{
    // Create and set the timer when to expire
    rtk_h5.timer_sync_retrans = OsAllocateTimer(h5_sync_retrans_timeout_handler);

    return 0;
}

int h5_free_sync_retrans_timer(void)
{
    return OsFreeTimer(rtk_h5.timer_sync_retrans);
}

int h5_start_sync_retrans_timer(void)
{
    return OsStartTimer(rtk_h5.timer_sync_retrans, SYNC_RETRANS_TIMEOUT_VALUE, 1);
}

int h5_stop_sync_retrans_timer(void)
{
    return OsStopTimer(rtk_h5.timer_sync_retrans);
}

/*
** h5 config retrans timer functions
*/
int h5_alloc_conf_retrans_timer(void)
{
    // Create and set the timer when to expire
    rtk_h5.timer_conf_retrans = OsAllocateTimer(h5_conf_retrans_timeout_handler);

    return 0;
}

int h5_free_conf_retrans_timer(void)
{
    return OsFreeTimer(rtk_h5.timer_conf_retrans);
}

int h5_start_conf_retrans_timer(void)
{
    return OsStartTimer(rtk_h5.timer_conf_retrans, CONF_RETRANS_TIMEOUT_VALUE, 1);
}

int h5_stop_conf_retrans_timer(void)
{
    return OsStopTimer(rtk_h5.timer_conf_retrans);
}

/*
** h5 wait controller baudrate ready timer functions
*/
int h5_alloc_wait_controller_baudrate_ready_timer(void)
{
    // Create and set the timer when to expire
    rtk_h5.timer_wait_ct_baudrate_ready = OsAllocateTimer(h5_wait_controller_baudrate_ready_timeout_handler);

    return 0;
}

int h5_free_wait_controller_baudrate_ready_timer(void)
{
    return OsFreeTimer(rtk_h5.timer_wait_ct_baudrate_ready);
}

int h5_start_wait_controller_baudrate_ready_timer(void)
{
    return OsStartTimer(rtk_h5.timer_wait_ct_baudrate_ready, WAIT_CT_BAUDRATE_READY_TIMEOUT_VALUE, 0);
}

int h5_stop_wait_controller_baudrate_ready_timer(void)
{
    return OsStopTimer(rtk_h5.timer_wait_ct_baudrate_ready);
}

/*
** h5 hw init ready timer functions
*/
int h5_alloc_hw_init_ready_timer(void)
{
    // Create and set the timer when to expire
    rtk_h5.timer_h5_hw_init_ready = OsAllocateTimer(h5_hw_init_ready_timeout_handler);

    return 0;
}

int h5_free_hw_init_ready_timer(void)
{
    return OsFreeTimer(rtk_h5.timer_h5_hw_init_ready);
}

int h5_start_hw_init_ready_timer(void)
{
    return OsStartTimer(rtk_h5.timer_h5_hw_init_ready, H5_HW_INIT_READY_TIMEOUT_VALUE, 0);
}

int h5_stop_hw_init_ready_timer(void)
{
    return OsStopTimer(rtk_h5.timer_h5_hw_init_ready);
}

/******************************************************************************
**  HCI H5 Services interface table
******************************************************************************/
const hci_h5_t hci_h5_int_func_table = {
    .h5_int_init = hci_h5_int_init,
    .h5_int_cleanup = hci_h5_cleanup,
    .h5_send_cmd = hci_h5_send_cmd,
    .h5_send_sync_cmd = hci_h5_send_sync_cmd,
    .h5_send_acl_data = hci_h5_send_acl_data,
    .h5_send_sco_data = hci_h5_send_sco_data,
    .h5_recv_msg = hci_h5_receive_msg,
    .h5_int_read_data = hci_h5_int_read_data,
};

const hci_h5_t *hci_get_h5_int_interface()
{
    return &hci_h5_int_func_table;
}
